package main

import (
	"ch05/classfile"
	"ch05/rtda"
	"fmt"
	"ch05/instructions/base"
	"ch05/instructions"
)

func interpreter (methodInfo *classfile.MemberInfo) {
	codeAttri := methodInfo.CodeAttribute()
	maxLocals := codeAttri.MaxLocals()
	maxStack := codeAttri.MaxStack()
	bytecode := codeAttri.Code()

	thread :=rtda.NewThread()
	frame := thread.NewFrame(maxLocals, maxStack)
	thread.PushFrame(frame)

	defer catchErr(frame)
	loop(thread,bytecode)
}
func loop(thread *rtda.Thread, bytecode []byte) {
	frame := thread.PopFrame()
	reader := &base.BytecodeReader{}
	for   {
		pc := frame.NextPc()
		thread.SetPc(pc)

		//decode
		reader.Reset(bytecode,pc)
		opcode := reader.ReadUint8()
		inst := instructions.NewInstruction(opcode)
		inst.FetchOperands(reader)
		frame.SetNextPc(reader.PC())

		//execute
		fmt.Printf("pc:%2d inst:%T %v\n",pc,inst,inst)
		inst.Execute(frame)

	}
}
func catchErr(frame *rtda.Frame) {
	if r:=recover();r!= nil {
		fmt.Printf("LocalVars:%v\n",frame.LocalVars())
		fmt.Printf("OperandStack:%v\n",frame.OperandStack())
		panic(r)
	}
}
